# vim:ts=4:sw=4:noet:
""" IR optimisers """

import c.compiler.cfg
from irvisit import IRVisitor
import c.compiler.ir as ir

class OptInline(IRVisitor):

	def __init__(self, compiler, mem, classes):
		self.mem = mem
		self.compiler = compiler
		self.classes = {}
		for c in classes:
			self.classes[c.name] = c

	def getIRMethod(self, clsname, methname):
		return self.compiler.getIRForMethod(clsname, methname)

	def doMethod(self, cls, meth):
		#print "iropt:do method", cls, meth
		self.clsname = cls
		self.meth = meth
		IRVisitor.doMethod(self, meth)

	def doIRReturn(self, node):
		r,v = self.doIRNode(node.value)
		if r:
			node.value = v
		return (None, None)

	def inlineCall(self, orig, new):
		#print " original:", orig, orig.args
		#print " new:", new
		#print "check inline", orig.name
		return (True, new)
	
	def doIRMessage(self, node):
		if node.recv:
			if ((isinstance(node.recv, ir.IRName)) and 
				  ((node.recv.name=="self") or
					 (self.mem.getGlobal(node.recv.name)))):
				if node.recv.name!="self":
					spycls = self.mem.getGlobal("Meta"+node.recv.name)
				else:
					spycls = self.mem.getGlobal(self.clsname)
				if not spycls:
					return (None, None)
				spymeth = spycls.getMethod(node.name)
				if spymeth and spymeth.name != self.meth.name:
					irmeth = self.getIRMethod(spymeth.incls.name, spymeth.name)
					if irmeth and irmeth.canInline():
						#print "possible inline of %s in %s>>%s" % (
						#		node.name, self.clsname, self.meth.name)
						#print " - using method %s>>%s" % (spymeth.incls.name, spymeth.name)
						code = irmeth.body.statements[0].value
						depcls = self.mem.getGlobal(self.clsname)
						depmeth = depcls.getMethod(self.meth.name)
						spymeth.addDependant(depcls, depmeth)
						return self.inlineCall(node, code)
			else:
				r, v = self.doIRNode(node.recv)
				if r: node.recv = v

		for i,a in enumerate(node.args):
			r,v = self.doIRNode(a)
			if r: node.args[i] = v
		return (None, None)

	def doIRPrimitive(self, node):
		for i,a in enumerate(node.args):
			r,v = self.doIRNode(a)
			if r: node.args[i] = v
		return (None, None)

	def doIRAssign(self, node):
		r,v = self.doIRNode(node.value)
		if r: node.value = v
		return (None, None)

	def doIRCascade(self, node):
		r,v = self.doIRNode(node.node)
		if r: node.node = v
		for i,c in enumerate(node.list):
			r,v = self.doIRNode(c)
			if r: node.list[i] = v
		return (None, None)

	def doIRInteger(self, node):
		return (None, None)
	
	def doIRString(self, node):
		return (None, None)
	
	def doIRSymbol(self, node):
		return (None, None)
	
	def doIRChar(self, node):
		return (None, None)
	
	def doIRName(self, node):
		return (None, None)

	def doIRArray(self, node):
		return (None, None)

